WasmバイナリをrunwasiとPodman/crun/WasmEdgeから実行してみた
DockerやKubernetesで利用されているコンテナランタイム containerd からは、shim を通じてruncやAWS Fargateで利用されているFirecrackerなど様々なコンテナ実行方法をサポートします。
数年前にDocker社のプレスリリースで話題になったのように、WebAssembly(Wasm)アプリも実行することができ、Wasm向けshimから runwasi を呼び出すほか、runc 向け shimから Wasm対応した crun を 呼び出す事もできます。
※ 図はIntroducing the Docker+Wasm Technical Preview | Docker から
本記事では、両ケースに対応する containerd をインストールしたあと、runwasi 方式とPodman&crun のそれぞれで実行します。
検証環境
- Ubuntu 22.04 x86(Amazon EC2を利用) 30GiB以上のストレージを推奨
- containerd : 1.7.13
- crun : 1.14.4.0.0.0.10-64ee
- wasmedge : 0.13.5
- podman : 3.4.4
事前準備
Ubuntu を用意
今回は Linux 上で Ubuntu 22.04(x86_64)を利用しました。 EBSのストレージサイズを 20GiBで起動したところ、ギリギリ容量不足になったため、30GiB程度は確保しておきましょう。
$ sudo apt update
containerd を用意
次に高レベルランタイムの containerd をインストールします。
GitHub レポジトリ second-state/wasmedge-containers-examples に containerd と Wasm(wasmedge)対応したcrunをインストールするスクリプトがあります。 containerd のバージョンだけ調整して流用します。
スクリプト内では、containerd のランタイムをデフォルトの runc
から crun
に変更するなどしています。
詳細はシェルスクリプトをご確認ください。
$ wget https://raw.githubusercontent.com/second-state/wasmedge-containers-examples/main/containerd/install.sh # バージョン変更 $ diff -u orig-install.sh install.sh --- orig-install.sh 2024-03-03 04:35:06.574460659 +0000 +++ install.sh 2024-03-03 04:35:16.262457855 +0000 @@ -20,7 +20,7 @@ echo -e "Starting installation ..." sudo apt update -export VERSION="1.5.7" +export VERSION="1.7.13" echo -e "Version: $VERSION" echo -e "Installing libseccomp2 ..." sudo apt install -y libseccomp2 $ bash install.sh ... # デフォルトランタイムを変更 $ grep crun /etc/containerd/* /etc/containerd/config.toml: default_runtime_name = "crun" /etc/containerd/config.toml: runtime = "crun" /etc/containerd/config.toml.rej:+ [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun] /etc/containerd/config.toml.rej:+ [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun.options] /etc/containerd/config.toml.rej:+ BinaryName = "crun" $ ls -1 /usr/local/bin/ containerd containerd-shim containerd-shim-runc-v1 containerd-shim-runc-v2 containerd-stress crictl critest crun ctd-decoder ctr wasmedge wasmedgec
crun のバージョン情報に Wasm 対応している旨も出力されていますね。
$ /usr/local/bin/crun -v crun version 1.14.4.0.0.0.10-64ee commit: 64ee22ce09e2879eaf346fd3bd03806a64b4acd6 rundir: /run/user/1000/crun spec: 1.0.0 +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +WASM:wasmedge +YAJL
containerd から hello-world コンテナを動かしてみましょう
$ sudo ctr images pull docker.io/library/hello-world:latest $ sudo ctr run --rm docker.io/library/hello-world:latest hello1 Hello from Docker! This message shows that your installation appears to be working correctly. ...
成功です。
Rustをインストール
次に Rust をインストールします。
Wasmバイナリの作成や関連プログラムのビルドのために必要です
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $ source "$HOME/.cargo/env"
WasmEdge からWasmバイナリを実行
WasmはもともとWebブラウザ上で実行することを想定して開発されました。その後、Wasmをブラウザの外でも実行するようなユースケースが増え、Wasmを様々な環境で汎用的に実行できるように策定されたのがWebAssembly System Interface(WASI)です。
WasmEdge はそのような WASI ランタイムの一つであり、Linux 上でWasmバイナリを実行できます。
Rust の hello-world プログラムをWasmをターゲットにコンパイルし、WasmEdge から実行してみましょう。
$ cargo new hello && cd hello $ cat src/main.rs fn main() { println!("Hello, world!"); } $ rustup target add wasm32-wasi $ cargo build --target wasm32-wasi Compiling hello v0.1.0 (/home/ubuntu/hello) Finished dev [unoptimized + debuginfo] target(s) in 0.17s $ cp target/wasm32-wasi/debug/hello.wasm . $ file hello.wasm hello.wasm: WebAssembly (wasm) binary module version 0x1 (MVP) $ wasmedge hello.wasm Hello, world!
無事成功しました。
runwasi からWasmバイナリを実行
runwasi は GitHub の containerd/runwasi レポジトリで管理されています。
同レポジトリ内の ./scripts/setup-linux.sh
で依存プログラムをインストールし、 build & make
でインストールします。
$ export RUNWASI_VERSOIN=0.4.0 $ wget https://github.com/containerd/runwasi/archive/refs/tags/containerd-shim-wasm/v${RUNWASI_VERSOIN}.tar.gz $ tar zxfv v${RUNWASI_VERSOIN}.tar.gz $ cd runwasi-containerd-shim-wasm-v${RUNWASI_VERSOIN}/ $ ./scripts/setup-linux.sh $ make build $ sudo make install
Wasmランタイムを提供する WasmEdge がテスト用の Wasmイメージを用意しているので活用します。
containerd 実行時にWasm向けランタイムを指定するだけです。
$ sudo ctr images pull docker.io/wasmedge/example-wasi:latest ... $ sudo ctr run --rm \ --runtime=io.containerd.wasmedge.v1 \ docker.io/wasmedge/example-wasi:latest example-wasi1 Random number: -2130467570 Random bytes: [149, 201, 92, 128, 17, 222, 132, 6, 106, 157, 200, 133, 23, 225, 22, 217, 92, 195, 246, 230, 143, 184, 60, 112, 170, 97, 2, 63, 230, 67, 195, 42, 56, 102, 16, 12, 90, 230, 97, 157, 233, 171, 24, 236, 237, 177, 126, 13, 39, 82, 50, 118, 56, 20, 88, 239, 119, 125, 230, 205, 247, 61, 218, 97, 121, 152, 158, 160, 15, 205, 132, 207, 145, 78, 184, 246, 123, 64, 213, 239, 19, 230, 104, 46, 11, 60, 198, 187, 124, 221, 211, 239, 33, 5, 167, 174, 164, 165, 167, 214, 4, 156, 74, 76, 58, 25, 27, 24, 58, 55, 246, 102, 161, 43, 53, 71, 157, 3, 31, 114, 232, 243, 239, 37, 171, 44, 68, 200] Printed from wasi: This is from a main function This is from a main function The env vars are as follows. PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin The args are as follows. /wasi_example_main.wasm File content is This is in a file
Podman/crun/WasmEdgeからWasmバイナリを実行
最後に、Podman から Wasm対応した crun を呼び出し Wasmバイナリを実行します。
内容的には、次の @utam0k さんの発表スライドと同等と思われます(発表を直接聞いたわけではありません)
Podman with WebAssembly - Speaker Deck
$ sudo apt install podman $ podman -v podman version 3.4.4
containerd と同じく Podman も低レベルランタイムにデフォルトでは runc を利用するため、Wasm対応した crun ランタイムで呼び出します。
$ podman --runtime /usr/local/bin/crun info | grep -A 9 ociRuntime ociRuntime: name: /usr/local/bin/crun package: Unknown path: /usr/local/bin/crun version: |- crun version 1.14.4.0.0.0.10-64ee commit: 64ee22ce09e2879eaf346fd3bd03806a64b4acd6 rundir: /run/user/1000/crun spec: 1.0.0 +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +WASM:wasmedge +YAJL
podman から hello-world イメージを呼び出します
$ podman run --rm hello-world Hello from Docker! This message shows that your installation appears to be working correctly. ...
次に、先程の Rust でコンパイルした "rust.wasm" ファイルを利用したDockerファイルを用意します。
FROM scratch COPY hello.wasm / ENTRYPOINT ["/hello.wasm"]
次に Wasmイメージであるというアノテーションとともにイメージをビルドします。
$ buildah build \ --annotation "module.wasm.image/variant=compat" \ -t hello-wasm . ... $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE localhost/hello-wasm latest 7af43b9e2ab4 8 seconds ago 1.74 MB docker.io/library/hello-world latest d2c94e258dcb 10 months ago 26.3 kB ...
crun ランタイムを指定して起動します
$ podman \ --runtime /usr/local/bin/crun run \ --rm localhost/hello-wasm Hello, world!
無事成功です。
コンテナランタイム is 何?
Amazon ECSのようなフルマネージドのコンテナ実行環境を利用し、アプリケーションをコンテナ化することにていると、コンテナランタイムを意識することはあまりありません。
そんな方にぴったりなのが、本日 2024/03/04 に発売される『[改訂新版]イラストでわかるDockerとKubernetes』です。
著者の徳永 航平氏はコンテナランタイムやイメージなどの開発に従事し、Container Runtime Meetupも運営されています。container2wasmの作者としてもおなじみですね。
約3年前に出版された初版に対するアマゾンの111件のレビューが、本書の素晴らしさを物語っています。
普段、触っている技術領域の一つ下のレイヤーにも興味を向けると、より深く対象を理解できるようになるかもしれません。